home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / isapiapp.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-29  |  13.7 KB  |  473 lines

  1. unit ISAPIApp;
  2.  
  3. interface
  4.  
  5. uses Windows, Classes, HTTPApp, ISAPI2;
  6.  
  7. type
  8.   TISAPIRequest = class(TWebRequest)
  9.   private
  10.     FECB: PEXTENSION_CONTROL_BLOCK;
  11.   protected
  12.     function GetStringVariable(Index: Integer): string; override;
  13.     function GetDateVariable(Index: Integer): TDateTime; override;
  14.     function GetIntegerVariable(Index: Integer): Integer; override;
  15.   public
  16.     constructor Create(AECB: PEXTENSION_CONTROL_BLOCK);
  17.     function GetFieldByName(const Name: string): string; override;
  18.     function ReadClient(var Buffer; Count: Integer): Integer; override;
  19.     function ReadString(Count: Integer): string; override;
  20.     function TranslateURI(const URI: string): string; override;
  21.     function WriteClient(var Buffer; Count: Integer): Integer; override;
  22.     function WriteString(const AString: string): Boolean; override;
  23.     property ECB: PEXTENSION_CONTROL_BLOCK read FECB;
  24.   end;
  25.  
  26.   TISAPIResponse = class(TWebResponse)
  27.   private
  28.     FStatusCode: Integer;
  29.     FStringVariables: array[0..MAX_STRINGS - 1] of string;
  30.     FIntegerVariables: array[0..MAX_INTEGERS - 1] of Integer;
  31.     FDateVariables: array[0..MAX_DATETIMES - 1] of TDateTime;
  32.     FContent: string;
  33.     FSent: Boolean;
  34.   protected
  35.     function GetContent: string; override;
  36.     function GetDateVariable(Index: Integer): TDateTime; override;
  37.     function GetIntegerVariable(Index: Integer): Integer; override;
  38.     function GetLogMessage: string; override;
  39.     function GetStatusCode: Integer; override;
  40.     function GetStringVariable(Index: Integer): string; override;
  41.     function Sent: Boolean; override;
  42.     procedure SetContent(const Value: string); override;
  43.     procedure SetDateVariable(Index: Integer; const Value: TDateTime); override;
  44.     procedure SetIntegerVariable(Index: Integer; Value: Integer); override;
  45.     procedure SetLogMessage(const Value: string); override;
  46.     procedure SetStatusCode(Value: Integer); override;
  47.     procedure SetStringVariable(Index: Integer; const Value: string); override;
  48.   public
  49.     constructor Create(HTTPRequest: TWebRequest);
  50.     procedure SendResponse; override;
  51.     procedure SendRedirect(const URI: string); override;
  52.     procedure SendStream(AStream: TStream); override;
  53.   end;
  54.  
  55.   TISAPIApplication = class(TWebApplication)
  56.   private
  57.     function NewRequest(var AECB: TEXTENSION_CONTROL_BLOCK): TISAPIRequest;
  58.     function NewResponse(ISAPIRequest: TISAPIRequest): TISAPIResponse;
  59.   public
  60.     // These are the entry points relayed from the ISAPI DLL imports
  61.     function GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL;
  62.     function HttpExtensionProc(var ECB: TEXTENSION_CONTROL_BLOCK): DWORD;
  63.     function TerminateExtension(dwFlags: DWORD): BOOL;
  64.   end;
  65.  
  66. function GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL; stdcall;
  67. function HttpExtensionProc(var ECB: TEXTENSION_CONTROL_BLOCK): DWORD; stdcall;
  68. function TerminateExtension(dwFlags: DWORD): BOOL; stdcall;
  69.  
  70. implementation
  71.  
  72. uses SysUtils, WebConst;
  73.  
  74. const
  75.   ServerVariables: array[0..28] of string = (
  76.     '',
  77.     'SERVER_PROTOCOL',
  78.     'URL',
  79.     '',
  80.     '',
  81.     '',
  82.     'HTTP_CACHE_CONTROL',
  83.     'HTTP_DATE',
  84.     'HTTP_ACCEPT',
  85.     'HTTP_FROM',
  86.     'HTTP_HOST',
  87.     'HTTP_IF_MODIFIED_SINCE',
  88.     'HTTP_REFERER',
  89.     'HTTP_USER_AGENT',
  90.     'HTTP_CONTENT_ENCODING',
  91.     'CONTENT_TYPE',
  92.     'CONTENT_LENGTH',
  93.     'HTTP_CONTENT_VERSION',
  94.     'HTTP_DERIVED_FROM',
  95.     'HTTP_EXPIRES',
  96.     'HTTP_TITLE',
  97.     'REMOTE_ADDR',
  98.     'REMOTE_HOST',
  99.     'SCRIPT_NAME',
  100.     'SERVER_PORT',
  101.     '',
  102.     'HTTP_CONNECTION',
  103.     'HTTP_COOKIE',
  104.     'HTTP_AUTHORIZATION');
  105.  
  106. { TISAPIRequest }
  107.  
  108. constructor TISAPIRequest.Create(AECB: PEXTENSION_CONTROL_BLOCK);
  109. begin
  110.   FECB := AECB;
  111.   inherited Create;
  112. end;
  113.  
  114. function TISAPIRequest.GetFieldByName(const Name: string): string;
  115. var
  116.   Buffer: array[0..4095] of Char;
  117.   Size: Integer;
  118. begin
  119.   Size := SizeOf(Buffer);
  120.   if ECB.GetServerVariable(ECB.ConnID, PChar(Name), @Buffer, Size) then
  121.   begin
  122.     if Size > 0 then Dec(Size);
  123.     SetString(Result, Buffer, Size);
  124.   end else Result := '';
  125. end;
  126.  
  127. function TISAPIRequest.GetStringVariable(Index: Integer): string;
  128. begin
  129.   case Index of
  130.     0: Result := ECB.lpszMethod;
  131.     3: Result := ECB.lpszQueryString;
  132.     4: Result := ECB.lpszPathInfo;
  133.     5: Result := ECB.lpszPathTranslated;
  134.     1..2, 6..24, 26..28: Result := GetFieldByName(ServerVariables[Index]);
  135.     25: if ECB.cbAvailable > 0 then
  136.       SetString(Result, PChar(ECB.lpbData), ECB.cbAvailable);
  137.    else
  138.       Result := '';
  139.   end;
  140. end;
  141.  
  142. function TISAPIRequest.GetDateVariable(Index: Integer): TDateTime;
  143. var
  144.   Value: string;
  145. begin
  146.   Value := GetStringVariable(Index);
  147.   if Value <> '' then
  148.     Result := ParseDate(Value)
  149.   else Result := -1;
  150. end;
  151.  
  152. function TISAPIRequest.GetIntegerVariable(Index: Integer): Integer;
  153. var
  154.   Value: string;
  155. begin
  156.   Value := GetStringVariable(Index);
  157.   if Value <> '' then
  158.     Result := StrToInt(Value)
  159.   else Result := -1;
  160. end;
  161.  
  162. function TISAPIRequest.ReadClient(var Buffer; Count: Integer): Integer;
  163. begin
  164.   Result := Count;
  165.   if not ECB.ReadClient(ECB.ConnID, @Buffer, Result) then
  166.     Result := -1;
  167. end;
  168.  
  169. function TISAPIRequest.ReadString(Count: Integer): string;
  170. var
  171.   Len: Integer;
  172. begin
  173.   SetLength(Result, Count);
  174.   Len := ReadClient(Pointer(Result)^, Count);
  175.   if Len > 0 then
  176.     SetLength(Result, Len)
  177.   else Result := '';
  178. end;
  179.  
  180. function TISAPIRequest.TranslateURI(const URI: string): string;
  181. var
  182.   PathBuffer: array[0..1023] of Char;
  183.   Size: Integer;
  184. begin
  185.   StrCopy(PathBuffer, PChar(URI));
  186.   Size := SizeOf(PathBuffer);
  187.   if ECB.ServerSupportFunction(ECB.ConnID, HSE_REQ_MAP_URL_TO_PATH,
  188.     @PathBuffer, @Size, nil) then
  189.     Result := PathBuffer
  190.   else Result := '';
  191. end;
  192.  
  193. function TISAPIRequest.WriteClient(var Buffer; Count: Integer): Integer;
  194. begin
  195.   Result := Count;
  196.   if not ECB.WriteClient(ECB.ConnID, @Buffer, Result, 0) then
  197.     Result := -1;
  198. end;
  199.  
  200. function TISAPIRequest.WriteString(const AString: string): Boolean;
  201. begin
  202.   Result := WriteClient(Pointer(AString)^, Length(AString)) = Length(AString);
  203. end;
  204.  
  205. { TISAPIResponse }
  206.  
  207. constructor TISAPIResponse.Create(HTTPRequest: TWebRequest);
  208. begin
  209.   inherited Create(HTTPRequest);
  210.   if FHTTPRequest.ProtocolVersion = '' then
  211.     Version := '1.0';
  212.   StatusCode := 200;
  213.   LastModified := -1;
  214.   Expires := -1;
  215.   Date := -1;
  216.   ContentType := 'text/html';
  217. end;
  218.  
  219. function TISAPIResponse.GetContent: string;
  220. begin
  221.   Result := FContent;
  222. end;
  223.  
  224. function TISAPIResponse.GetDateVariable(Index: Integer): TDateTime;
  225. begin
  226.   if (Index >= Low(FDateVariables)) and (Index <= High(FDateVariables)) then
  227.     Result := FDateVariables[Index]
  228.   else Result := 0.0;
  229. end;
  230.  
  231. function TISAPIResponse.GetIntegerVariable(Index: Integer): Integer;
  232. begin
  233.   if (Index >= Low(FIntegerVariables)) and (Index <= High(FIntegerVariables)) then
  234.     Result := FIntegerVariables[Index]
  235.   else Result := -1;
  236. end;
  237.  
  238. function TISAPIResponse.GetLogMessage: string;
  239. begin
  240.   Result := TISAPIRequest(HTTPRequest).ECB.lpszLogData;
  241. end;
  242.  
  243. function TISAPIResponse.GetStatusCode: Integer;
  244. begin
  245.   Result := FStatusCode;
  246. end;
  247.  
  248. function TISAPIResponse.GetStringVariable(Index: Integer): string;
  249. begin
  250.   if (Index >= Low(FStringVariables)) and (Index <= High(FStringVariables)) then
  251.     Result := FStringVariables[Index];
  252. end;
  253.  
  254. function TISAPIResponse.Sent: Boolean;
  255. begin
  256.   Result := FSent;
  257. end;
  258.  
  259. procedure TISAPIResponse.SetContent(const Value: string);
  260. begin
  261.   FContent := Value;
  262.   ContentLength := Length(FContent);
  263. end;
  264.  
  265. procedure TISAPIResponse.SetDateVariable(Index: Integer; const Value: TDateTime);
  266. begin
  267.   if (Index >= Low(FDateVariables)) and (Index <= High(FDateVariables)) then
  268.     if Value <> FDateVariables[Index] then
  269.       FDateVariables[Index] := Value;
  270. end;
  271.  
  272. procedure TISAPIResponse.SetIntegerVariable(Index: Integer; Value: Integer);
  273. begin
  274.   if (Index >= Low(FIntegerVariables)) and (Index <= High(FIntegerVariables)) then
  275.     if Value <> FIntegerVariables[Index] then
  276.       FIntegerVariables[Index] := Value;
  277. end;
  278.  
  279. procedure TISAPIResponse.SetLogMessage(const Value: string);
  280. begin
  281.   StrPLCopy(TISAPIRequest(HTTPRequest).ECB.lpszLogData, Value, HSE_LOG_BUFFER_LEN);
  282. end;
  283.  
  284. {!! Strings not to be resourced !!}
  285. procedure TISAPIResponse.SetStatusCode(Value: Integer);
  286. begin
  287.   if FStatusCode <> Value then
  288.   begin
  289.     FStatusCode := Value;
  290.     ReasonString := StatusString(Value);
  291.   end;
  292. end;
  293.  
  294. procedure TISAPIResponse.SetStringVariable(Index: Integer; const Value: string);
  295. begin
  296.   if (Index >= Low(FStringVariables)) and (Index <= High(FStringVariables)) then
  297.     FStringVariables[Index] := Value;
  298. end;
  299.  
  300. procedure TISAPIResponse.SendResponse;
  301. var
  302.   StatusString: string;
  303.   Headers: string;
  304.  
  305.   procedure AddHeaderItem(const Item, FormatStr: string);
  306.   begin
  307.     if Item <> '' then
  308.       Headers := Headers + Format(FormatStr, [Item]);
  309.   end;
  310.  
  311. begin
  312.   if HTTPRequest.ProtocolVersion <> '' then
  313.   begin
  314.     TISAPIRequest(HTTPRequest).ECB.dwHttpStatusCode := StatusCode;
  315.     if (ReasonString <> '') and (StatusCode > 0) then
  316.       StatusString := Format('%d %s', [StatusCode, ReasonString])
  317.     else StatusString := '200 OK';
  318.     AddHeaderItem(Allow, 'Allow: %s'#13#10);
  319.     AddHeaderItem(SetCookie, 'Set-Cookie: %s'#13#10);
  320.     AddHeaderItem(DerivedFrom, 'Derived-From: %s'#13#10);
  321.     if Expires > 0 then
  322.       Headers := Headers +
  323.         FormatDateTime('"Expires: "' + DateFormat + ' "GMT"'#13#10, Expires);
  324.     if LastModified > 0 then
  325.       Headers := Headers +
  326.         FormatDateTime('"Last-Modified: "' + DateFormat + ' "GMT"'#13#10, LastModified);
  327.     AddHeaderItem(Title, 'Title: %s'#13#10);
  328.     AddHeaderItem(WWWAuthenticate, 'WWW-Authenticate: %s'#13#10);
  329.     AddCustomHeaders(Headers);
  330.     AddHeaderItem(ContentVersion, 'Content-Version: %s'#13#10);
  331.     AddHeaderItem(ContentEncoding, 'Content-Encoding: %s'#13#10);
  332.     AddHeaderItem(ContentType, 'Content-Type: %s'#13#10);
  333.     if (Content <> '') or (ContentStream <> nil) then
  334.       AddHeaderItem(IntToStr(ContentLength), 'Content-Length: %s'#13#10);
  335.     Headers := Headers + 'Content:'#13#10#13#10;
  336.     with TISAPIRequest(FHTTPRequest) do
  337.       ECB.ServerSupportFunction(ECB.ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
  338.         PChar(StatusString), nil, LPDWORD(Headers));
  339.   end;
  340.   if ContentStream = nil then
  341.     HTTPRequest.WriteString(Content)
  342.   else if ContentStream <> nil then
  343.   begin
  344.     SendStream(ContentStream);
  345.     ContentStream := nil; // Drop the stream
  346.   end;
  347.   FSent := True;
  348. end;
  349.  
  350. procedure TISAPIResponse.SendRedirect(const URI: string);
  351. begin
  352.   with TISAPIRequest(FHTTPRequest) do
  353.     ECB.ServerSupportFunction(ECB.ConnID, HSE_REQ_SEND_URL_REDIRECT_RESP,
  354.       PChar(URI), nil, nil);
  355.   FSent := True;
  356. end;
  357.  
  358. procedure TISAPIResponse.SendStream(AStream: TStream);
  359. var
  360.   Buffer: array[0..8191] of Byte;
  361.   BytesToSend: Integer;
  362. begin
  363.   while AStream.Position < AStream.Size do
  364.   begin
  365.     BytesToSend := AStream.Read(Buffer, SizeOf(Buffer));
  366.     FHTTPRequest.WriteClient(Buffer, BytesToSend);
  367.   end;
  368. end;
  369.  
  370. { TISAPIApplication }
  371.  
  372. procedure HandleServerException(E: Exception; var ECB: TEXTENSION_CONTROL_BLOCK);
  373. var
  374.   ResultText, ResultHeaders: string;
  375.   Size: Integer;
  376. begin
  377.   ECB.dwHTTPStatusCode := 500;
  378.   ResultText := Format(sInternalServerError, [E.ClassName, E.Message]);
  379.   ResultHeaders := Format(
  380.     'Content-Type: text/html'#13#10 +     //Not resourced
  381.     'Content-Length: %d'#13#10 +          //Not resourced
  382.     'Content:'#13#10#13#10, [Length(ResultText)]); //Not resourced
  383.   ECB.ServerSupportFunction(ECB.ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
  384.     PChar('500 ' + E.Message), @Size, LPDWORD(ResultHeaders));
  385.   Size := Length(ResultText);
  386.   ECB.WriteClient(ECB.ConnID, Pointer(ResultText), Size, 0);
  387. end;
  388.  
  389. function TISAPIApplication.GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL;
  390. begin
  391.   try
  392.     Ver.dwExtensionVersion := MakeLong(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  393.     StrLCopy(Ver.lpszExtensionDesc, PChar(Title), HSE_MAX_EXT_DLL_NAME_LEN);
  394.     Result := True;
  395.   except
  396.     Result := False;
  397.   end;
  398. end;
  399.  
  400. function TISAPIApplication.HttpExtensionProc(var ECB: TEXTENSION_CONTROL_BLOCK): DWORD;
  401. var
  402.   HTTPRequest: TISAPIRequest;
  403.   HTTPResponse: TISAPIResponse;
  404. begin
  405.   try
  406.     HTTPRequest := NewRequest(ECB);
  407.     try
  408.       HTTPResponse := NewResponse(HTTPRequest);
  409.       try
  410.         if HandleRequest(HTTPRequest, HTTPResponse) then
  411.           Result := HSE_STATUS_SUCCESS
  412.         else Result := HSE_STATUS_ERROR;
  413.       finally
  414.         HTTPResponse.Free;
  415.       end;
  416.     finally
  417.       HTTPRequest.Free;
  418.     end;
  419.   except
  420.     HandleServerException(Exception(ExceptObject), ECB);
  421.     Result := HSE_STATUS_ERROR;
  422.   end;
  423. end;
  424.  
  425. function TISAPIApplication.NewRequest(var AECB: TEXTENSION_CONTROL_BLOCK): TISAPIRequest;
  426. begin
  427.   Result := TISAPIRequest.Create(@AECB);
  428. end;
  429.  
  430. function TISAPIApplication.NewResponse(ISAPIRequest: TISAPIRequest): TISAPIResponse;
  431. begin
  432.   Result := TISAPIResponse.Create(ISAPIRequest);
  433. end;
  434.  
  435. function TISAPIApplication.TerminateExtension(dwFlags: DWORD): BOOL;
  436. begin
  437.   Result := True;
  438. end;
  439.  
  440. // ISAPI interface
  441.  
  442. function GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL;
  443. begin
  444.   Result := (Application as TISAPIApplication).GetExtensionVersion(Ver);
  445. end;
  446.  
  447. function HttpExtensionProc(var ECB: TEXTENSION_CONTROL_BLOCK): DWORD;
  448. begin
  449.   Result := (Application as TISAPIApplication).HttpExtensionProc(ECB);
  450. end;
  451.  
  452. function TerminateExtension(dwFlags: DWORD): BOOL;
  453. begin
  454.   Result := (Application as TISAPIApplication).TerminateExtension(dwFlags);
  455. end;
  456.  
  457. procedure InitApplication;
  458. begin
  459.   Application := TISAPIApplication.Create(nil);
  460. end;
  461.  
  462. procedure DoneApplication;
  463. begin
  464.   Application.Free;
  465.   Application := nil;
  466. end;
  467.  
  468. initialization
  469.   InitApplication;
  470. finalization
  471.   DoneApplication;
  472. end.
  473.